<script>
    // 全局获取每一个依赖函数
    let activeEffect

    class Dep {
        subscribers = new Set()

        // 收集依赖
        depend() {
            // 当有值时 不会重复调用
            if (activeEffect) {
                this.subscribers.add(activeEffect)
            }
        }

        // 通知更新依赖
        notify() {
            // 通知每一项依赖更新
            this.subscribers.forEach(effect => {
                effect()
            })
        }
    }

    function watchEffect(effect) {
        // effect 就是调用的参数函数
        activeEffect = effect
        effect()
        // 调用后清空
        activeEffect = null
    }

    // 存储要响应式数据的数据
    const targetMap = new WeakMap()

    const reactiveHandlers = {
        get(target, key, receiver) {
            const dep = getDep(target, key)
            // 加入依赖
            dep.depend()
            return Reflect.get(target, key, receiver)
        },
        set(target, key, value, receiver) {
            const dep = getDep(target, key)
            // 通知依赖更新
            dep.notify()
            console.log(`${key}的新值为: ${value}`)
            // 需要返回一个布尔值来指示此操作是否成功
            const result = Reflect.get(target, key, value, receiver)

            return result
        }
    }

    // 响应时函数
    function reactive(raw) {
        // vue2响应时实现
        // Object.keys(raw).forEach(KEY => {
        //     const dep = new Dep()
        //     let value = raw[KEY]

        //     Object.defineProperty(raw, KEY, {
        //         get() {
        //             return value
        //         },
        //         set(newV) {
        //             console.log(KEY + '被修改,新值为: ' + newV)
        //             value = newV
        //             dep.notify()
        //         }
        //     })
        // })

        // // 处理完相应时候 返回数据
        // return raw


        // vue3 proxy 代理
        return new Proxy(raw, reactiveHandlers)
    }

    // reactive 响应时更新
    const state = reactive({
        count: 0
    })

    console.log('state ==> ', state)

    watchEffect(() => {
        // debugger
        console.log(state.count)
    })


    // 使用WeakMap只能使用对象作为键
    // WeakMap的好处是如果这个目标对象它本身不在可以从任何代码访问 这个目标对象会被垃圾回收

    function getDep(target, key) {
        let depsMap = targetMap.get(target)
        // 如果缓存中不存在  表示还没有进行依赖收集
        if (!depsMap) {
            // 创建一个map对象
            depsMap = new Map()
            // 存储到响应时对象缓存中
            targetMap.set(target, depsMap)
        }

        let dep = depsMap.get(key)

        // 如果dep为空 表示还没有被依赖收集
        if (!dep) {
            dep = new Dep()
            depsMap.set(key, dep)
        }

        return dep
    }
</script>